#ifndef __TDP2_RC5_SM_HPP__
#define __TDP2_RC5_SM_HPP__

#include "tdp2.hpp"
#include "tdp2_rc5_config.hpp"

namespace TDP
{
	namespace Compression
	{
		namespace RC5
		{
			namespace StructuredModel
			{
				static const int ValRun0_k		= 0;
				static const int ValRun1_k		= 1;
				static const int Val1_k			= 2;
				static const int Val2_3_k		= 3;
				static const int Val4_7_k		= 4;
				static const int Val8_15_k		= 5;
				static const int Val16_31_k		= 6;
				static const int Val32_63_k		= 7;
				static const int Val64_127_k	= 8;
				static const int Val128_255_k	= 9;

				static const int M_Base_k		= 0;
				static const int M_2_3_k		= 1;
				static const int M_4_7_k		= 2;
				static const int M_8_15_k		= 3;
				static const int M_16_31_k		= 4;
				static const int M_32_63_k		= 5;
				static const int M_64_127_k		= 6;
				static const int M_128_255_k	= 7;

				static const unsigned int ProbPoolOffsets_k[] = {0, 10, 12, 16, 24, 40, 72, 136};
				static const unsigned int ProbPoolCounts_k[] = {10, 2,  4,  8, 16, 32, 64, 128};

				struct ProbabilityPool
				{
					UInt32 ptotals[8];
					UInt16 probPool[264];

					void Init();
					void UpdateProbabilities(unsigned int model, UInt32 symbol);
				};
			}
		}
	}
}

namespace TDP
{
	namespace Compression
	{
		namespace RC5
		{
			namespace StructuredModel
			{
				inline void ProbabilityPool::UpdateProbabilities(unsigned int model, UInt32 symbol)
				{
					UInt16 *probs = this->probPool + ProbPoolOffsets_k[model];

					this->ptotals[model] += IncrementTable_k[model];
					probs[symbol] += IncrementTable_k[model];

					if(this->ptotals[model] >= ProbabilityMax_k)
					{
						// Normalize
						UInt32 t = 0;
						for(unsigned int i=0;i<ProbPoolCounts_k[model];i++)
						{
							probs[i] = (probs[i] + 1) >> 1;
							t += probs[i];
						}
						this->ptotals[model] = t;
					}
				}

				inline void ProbabilityPool::Init()
				{
					int n = 0;
					for(int i=0;i<8;i++)
					{
						unsigned int c = ProbPoolCounts_k[i];
						for(unsigned int j=0;j<c;j++)
							this->probPool[n++] = static_cast<UInt16>(IncrementTable_k[i]);
						this->ptotals[i] = static_cast<UInt32>(IncrementTable_k[i] * c);
					}
				}
			}
		}
	}
}

#endif
